package com.funtest.shard.database.policy;

import com.alibaba.druid.pool.DruidDataSource;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.api.config.sharding.ShardingRuleConfiguration;
import org.apache.shardingsphere.api.config.sharding.TableRuleConfiguration;
import org.apache.shardingsphere.api.config.sharding.strategy.StandardShardingStrategyConfiguration;
import org.apache.shardingsphere.shardingjdbc.api.ShardingDataSourceFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * @Author: flathead
 * @Date: 2021/4/30 17:20
 */
@Component
@Slf4j
public class CustomerDataSourceFactory {

    @Value("${shard.jdbc.ds0.url}")
    private String dsOUrl;
    @Value("${shard.jdbc.ds1.url}")
    private String ds1Url;

    @Value("${mysql.username}")
    private String mysqlUserName;

    @Value("${mysql.password}")
    private String mysqlPassword;

    @Value("${mysql.driver.class}")
    private String driverClassName;

    @Value("${spring.jpa.hibernate.ddl-auto}")
    private String ddlDef;


    /**
     * 设置数据源ds0
     */
    @Bean(name = "ds0", initMethod = "init", destroyMethod = "close")
    public DruidDataSource getDs0Source() throws SQLException {
        DruidDataSource dataSource0 = new DruidDataSource();
        dataSource0.setDriverClassName(driverClassName);
        dataSource0.setUrl(dsOUrl);
        dataSource0.setUsername(mysqlUserName);
        dataSource0.setPassword(mysqlPassword);
        dataSource0.setInitialSize(5);
        dataSource0.setMaxActive(20);
        dataSource0.setMinIdle(10);
        dataSource0.setMaxWait(30000);
        dataSource0.setFilters("stat,wall");
        Properties properties = new Properties();
        properties.setProperty("connectTimeout", "2000");
        properties.setProperty("socketTimeout", "600000");
        properties.setProperty("spring.jpa.hibernate.ddl-auto", ddlDef);
        dataSource0.setConnectProperties(properties);
        return dataSource0;
    }

    /**
     * 设置数据源ds1
     */
    @Bean(name = "ds1", initMethod = "init", destroyMethod = "close")
    public DruidDataSource getDs1Source() throws SQLException {
        DruidDataSource dataSource1 = new DruidDataSource();
        dataSource1.setDriverClassName(driverClassName);
        dataSource1.setUrl(ds1Url);
        dataSource1.setUsername(mysqlUserName);
        dataSource1.setPassword(mysqlPassword);
        dataSource1.setInitialSize(5);
        dataSource1.setMaxActive(20);
        dataSource1.setMinIdle(10);
        dataSource1.setMaxWait(30000);
        dataSource1.setFilters("stat,wall");
        Properties properties = new Properties();
        properties.setProperty("connectTimeout", "2000");
        properties.setProperty("socketTimeout", "600000");
        properties.setProperty("spring.jpa.hibernate.ddl-auto", ddlDef);
        dataSource1.setConnectProperties(properties);
        return dataSource1;
    }

    /**
     * 分片逻辑名称前缀 shard 分表
     */
    @Primary
    @Bean(name = "shardingDataSource")
    public DataSource shardingDataSource(@Qualifier("ds0") DruidDataSource ds0, @Qualifier("ds1") DruidDataSource ds1) {
        // 获取数据源对象
        Properties properties = new Properties();
        properties.setProperty("max.connections.size.per.query", "10");
//        if (devMode.equals("dao-dev")) {
//            // dev  环境开启此参数
//            properties.setProperty("sql.show", "true");
//        }
        DataSource dataSource = null;
        try {
            Map<String, DataSource> targetDataSource = new HashMap<>();
            targetDataSource.put("ds0", ds0);
            targetDataSource.put("ds1", ds1);
            //设置分表规则，订单后两位，路由至0-1，2张表
            ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
            //必须设置默认数据源
            shardingRuleConfig.setDefaultDataSourceName("ds0");
            shardingRuleConfig.getTableRuleConfigs().add(orderRuleConfig());
            //shardingRuleConfig.getTableRuleConfigs().add(orderItemRuleConfig());
            //设置分库规则，订单/2，偶數ds0，奇數ds1
            shardingRuleConfig.setDefaultDatabaseShardingStrategyConfig(new StandardShardingStrategyConfiguration("order_id", ShardingDBAlgorithm.DATABASE_SHARDING_ALGORITHM));
            //绑定表
            //shardingRuleConfig.getBindingTableGroups().add("t_order, t_order_item");
            shardingRuleConfig.getBindingTableGroups().add("t_order");
            //创建sharding数据源
            dataSource = ShardingDataSourceFactory.createDataSource(targetDataSource, shardingRuleConfig, properties);
        } catch (SQLException e) {
            e.printStackTrace();
            log.error("MYSQL shardconfig 数据源初始化失败");
        }
        log.info("MYSQL shardconfig 数据源初始化成功");
        return dataSource;
    }

    /**
     * 设置订单表分表规则
     */
    private TableRuleConfiguration orderRuleConfig() {
        TableRuleConfiguration tableRuleConfig = new TableRuleConfiguration("t_order", "ds${0..1}.t_order_${0..1}");
        StandardShardingStrategyConfiguration tableRule = new StandardShardingStrategyConfiguration("order_id", new OrderCheckShardingTableAlgorithm());
        tableRuleConfig.setTableShardingStrategyConfig(tableRule);
        return tableRuleConfig;
    }

    /**
     * 设置订单商品表分表规则
     */
    private TableRuleConfiguration orderItemRuleConfig() {
        TableRuleConfiguration tableRuleConfig = new TableRuleConfiguration("t_order_item", "ds0.t_order_item_${0..1}");
        StandardShardingStrategyConfiguration tableRule = new StandardShardingStrategyConfiguration("order_id", new OrderCheckShardingTableAlgorithm());
        tableRuleConfig.setTableShardingStrategyConfig(tableRule);
        return tableRuleConfig;
    }



}
